package dao

import (
	"context"
	"errors"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"seichat/biz"
	"seichat/models"
	"strings"
)

type RelationDao interface {
	GetRelationListByOwnerId(ctx context.Context, ownerId uint, relationType int) ([]*models.Relation, error)
	FindFriendListByUserId(ctx context.Context, userId uint, relationType int) ([]*models.User, error)
	FindRelationByUserIdAndTargetId(ctx context.Context, ownerId, targetId uint, relationType int) (*models.Relation, bool)
	AddFriend(ctx context.Context, userID, targetID uint) error
	FindUsersIdByGroupId(ctx context.Context, groupId uint) ([]*models.Relation, error)
}

type GormRelationDao struct {
	DB *gorm.DB
}

func NewRelationDao(db *gorm.DB) RelationDao {
	return &GormRelationDao{DB: db}
}

// GetRelationListByOwnerId 根据type 类型和 用户id 返回对应关系表
func (r *GormRelationDao) GetRelationListByOwnerId(ctx context.Context, ownerId uint, relationType int) ([]*models.Relation, error) {
	var relations []*models.Relation
	tx := r.DB.WithContext(ctx).Where("owner_id = ? AND type = ?", ownerId, relationType).Find(&relations)
	if err := handleGormError(tx); err != nil {
		return nil, err
	}
	if tx.RowsAffected == 0 {
		return nil, biz.RecordNotFound
	}
	return relations, nil
}

// FindFriendListByUserId 根据用户id获取好友列表
func (r *GormRelationDao) FindFriendListByUserId(ctx context.Context, userId uint, relationType int) ([]*models.User, error) {
	var relations []models.Relation
	tx := r.DB.WithContext(ctx).Where("owner_id = ? AND type = ?", userId, relationType).Find(&relations)
	if err := EnsureRelationRecordFound(tx); err != nil {
		zap.S().Warnw("未查询到Relation数据", "userId", userId)
		return []*models.User{}, nil
	}
	var targetIDs []uint
	for _, rel := range relations {
		targetIDs = append(targetIDs, rel.TargetID)
	}
	var users []*models.User
	tx = r.DB.Where("id IN ?", targetIDs).Find(&users)
	if err := EnsureRelationRecordFound(tx); err != nil {
		zap.S().Warnw("未查询到Relation对应的好友数据", "userId", userId)
		return []*models.User{}, nil
	}
	return users, nil
}

// FindRelationByUserIdAndTargetId 校验群关系是否存在
func (r *GormRelationDao) FindRelationByUserIdAndTargetId(ctx context.Context, ownerId, targetId uint, relationType int) (*models.Relation, bool) {
	relation := models.Relation{}
	tx := r.DB.WithContext(ctx).Where("owner_id = ? and target_id = ? and type = ?", ownerId, targetId, relationType).First(&relation)
	if err := handleGormError(tx); err != nil {
		zap.S().Error(err.Error())
		return nil, false
	}
	if tx.RowsAffected == 0 {
		return nil, false
	}
	return &relation, true
}

// AddFriend 添加好友
func (r *GormRelationDao) AddFriend(ctx context.Context, userID, targetID uint) error {
	// 使用唯一索引替代查重
	relation := models.Relation{
		OwnerId:  userID,
		TargetID: targetID,
		Type:     1,
	}
	tx := r.DB.WithContext(ctx).Begin()
	if err := tx.Create(&relation).Error; err != nil {
		tx.Rollback()
		if strings.Contains(err.Error(), "duplicate key") {
			return biz.RepeatAddFriendError
		}
		zap.S().Errorw("添加好友失败", "error", err)
		return biz.AddFriendError
	}
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		zap.S().Errorw("事务提交失败", "error", err)
		return err
	}
	return nil
}

func (r *GormRelationDao) FindUsersIdByGroupId(ctx context.Context, groupId uint) ([]*models.Relation, error) {
	relation := make([]*models.Relation, 0)
	if tx := r.DB.WithContext(ctx).Where("target_id = ? and type = 2", groupId).Find(&relation); tx.RowsAffected == 0 {
		if err := handleGormError(tx); err != nil {
			return nil, errors.New("未查询到群成员")
		}
		return nil, biz.DBError
	}
	return relation, nil
}
